package com.hj.springframework3.jdbc.tx;

import com.hj.springframework3.exception.TransactionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.sql.DataSource;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.SQLException;

/**
 * @Author : hujing
 * @Date: 2025/7/11 11:14
 * @Description: 数据源事物管理器
 */
public class DataSourceTransactionManager implements PlatformTransactionManager, InvocationHandler {

    static final ThreadLocal<TransactionStatus> transactionStatus = new ThreadLocal<>();
    final Logger logger = LoggerFactory.getLogger(getClass());
    final DataSource dataSource;

    public DataSourceTransactionManager(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 获取事物状态
        TransactionStatus ts = transactionStatus.get();
        if (ts == null) {
            // 当前无事务,开启新事务
            try(Connection connection = dataSource.getConnection()){
                final boolean autoCommit = connection.getAutoCommit();
                // 自动提交为true时,关闭自动提交
                if (autoCommit){
                    connection.setAutoCommit(false);
                }
                try{
                    transactionStatus.set(new TransactionStatus(connection));
                    Object r = method.invoke(proxy, args);
                    connection.commit();
                    return r;
                }catch (Exception e){
                    TransactionException te = new TransactionException(e.getCause());
                    // 回滚事物
                    try{
                        connection.rollback();
                    }catch (SQLException sqlException){
                        te.addSuppressed(sqlException);
                    }
                    throw te;
                }
                finally{
                    transactionStatus.remove();
                    if (autoCommit){
                        connection.setAutoCommit(true);
                    }
                }
            }
        }else{
            return method.invoke(proxy,args);
        }
    }
}
